Fix a regression in hvm_pio_assist() when booting Windows
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Wed, 5 Apr 2006 11:23:49 +0000 (12:23 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Wed, 5 Apr 2006 11:23:49 +0000 (12:23 +0100)
on VT-x. Clean up the function also.

Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/io.c

index fd9ff611dffcd76346476899cfd31104ca63f74e..a6cde8ee267e01aadfe6833ac7a8ecee3e95f332 100644 (file)
@@ -365,57 +365,46 @@ static void hvm_pio_assist(struct cpu_user_regs *regs, ioreq_t *p,
     unsigned long old_eax;
     int sign = p->df ? -1 : 1;
 
-    if (p->pdata_valid || (mmio_opp->flags & OVERLAP)) {
-        if (mmio_opp->flags & REPZ)
+    if ( p->pdata_valid || (mmio_opp->flags & OVERLAP) )
+    {
+        if ( mmio_opp->flags & REPZ )
             regs->ecx -= p->count;
-        if (p->dir == IOREQ_READ) {
+        if ( p->dir == IOREQ_READ )
+        {
             regs->edi += sign * p->count * p->size;
-
-            if (mmio_opp->flags & OVERLAP) {
-                /* 
-                 * If we are doing in IN and it's overlapping a page boundary, 
-                 * we need to copy the data back to user's page with hvm_copy. 
-                 * Note that overlap * can only be set with paging enabled, so 
-                 * we don't need to worry about * real-mode stuff.  
-                 */
-                unsigned long addr;
-                {
-                    /* 
-                    * We completely ignore segment registers here - 
-                     * it's not a good idea. We also may use upper bits
-                     * in edi when in 16-bit real/protected mode.
-                     * We really need to get the actual address back from
-                     * the arch-dependant HVM portion.
-                     */
-                    struct vcpu *v = current;
-                    if (hvm_realmode(v))
-                        __hvm_bug(regs);
-                }
-                addr = regs->edi;
+            if ( mmio_opp->flags & OVERLAP )
+            {
+                unsigned long addr = regs->edi;
+                if (hvm_realmode(current))
+                    addr += regs->es << 4;
                 if (sign > 0)
                     addr -= p->size;
                 hvm_copy(&p->u.data, addr, p->size, HVM_COPY_OUT);
             }
-        } else
+        }
+        else /* p->dir == IOREQ_WRITE */
+        {
+            ASSERT(p->dir == IOREQ_WRITE);
             regs->esi += sign * p->count * p->size;
-
-    } else {
-        if (p->dir == IOREQ_READ) {
-            old_eax = regs->eax;
-            switch (p->size) {
-            case 1:
-                regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
-                break;
-            case 2:
-                regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
-                break;
-            case 4:
-                regs->eax = (p->u.data & 0xffffffff);
-                break;
-            default:
-                printk("Error: %s unknown port size\n", __FUNCTION__);
-                domain_crash_synchronous();
-            }
+        }
+    }
+    else if ( p->dir == IOREQ_READ )
+    {
+        old_eax = regs->eax;
+        switch ( p->size )
+        {
+        case 1:
+            regs->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
+            break;
+        case 2:
+            regs->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
+            break;
+        case 4:
+            regs->eax = (p->u.data & 0xffffffff);
+            break;
+        default:
+            printk("Error: %s unknown port size\n", __FUNCTION__);
+            domain_crash_synchronous();
         }
     }
 }